package com.iplant.wms.serviceImpl.dao.wms;

import com.iplant.base.utils.annotation.dao.DBBaseDAO;
import com.iplant.base.utils.cache.CacheUtils;
import com.iplant.basic.service.po.fmc.FMCFactory;
import com.iplant.basic.service.po.mss.MSSMaterial;
import com.iplant.basic.service.po.mss.MSSUnit;
import com.iplant.wms.service.po.mfs.*;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.BaseDAO;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.wms.service.po.wms.WMSStock;
import com.iplant.wms.service.po.wms.WMSStockRecord;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

@Slf4j
@DBBaseDAO(WMSStockRecord.class)
public class WMSStockRecordDAO extends BaseDAO {

    private static WMSStockRecordDAO Instance = null;

    private WMSStockRecordDAO() {
        super("");
        this.Init();
    }

    public static WMSStockRecordDAO getInstance() {
        if (Instance == null) {
            synchronized (WMSStockRecordDAO.class) {
                if (Instance == null) {
                    Instance = new WMSStockRecordDAO();
                }
            }
        }
        return Instance;
    }


    public WMSStockRecord WMS_QueryStockRecord(BMSEmployee wLoginUser, int wStoreStationID,
                                               int wMaterialID, int wBatchRecordID, String wBatchRecordCode, OutResult<Integer> wErrorCode) {
        WMSStockRecord wResult = new WMSStockRecord();

        if (wStoreStationID <= 0 || wMaterialID <= 0 || wBatchRecordID <= 0) {
            wErrorCode.Result = ExceptionTypes.Parameter.getValue();
            return wResult;
        }

        Map<String, Object> wParams = new HashMap<>();
        wParams.put("StoreStationID", wStoreStationID);
        wParams.put("MaterialID", wMaterialID);
        wParams.put("BatchRecordID", wBatchRecordID);
        wParams.put("BatchRecordCode", wBatchRecordCode);

        wResult = this.SelectPO(wLoginUser, wParams, wErrorCode);

        return wResult;
    }


    public List<WMSStockRecord> WMS_QueryStockRecordList(BMSEmployee wLoginUser, int wFactoryID, int wStoreID, int wStoreRegionID, int wStoreAreaID,
                                                         int wStoreShelfID, int wStoreStationID, List<Integer> wMaterialIDList,
                                                         int wBatchRecordID, String wBatchRecordCode, String wProjectNo, int wCustomerID, int wSupplierID, int wStockTypeID, int wStockStatus, Pagination wPagination,
                                                         OutResult<Integer> wErrorCode) {
        Map<String, Object> wParams = new HashMap<String, Object>();
        wParams.put("FactoryID", wFactoryID);
        wParams.put("CustomerID", wCustomerID);
        wParams.put("SupplierID", wSupplierID);
        wParams.put("StockTypeID", wStockTypeID);
        wParams.put("StockStatus", wStockStatus);
        wParams.put("StoreRegionID", wStoreRegionID);
        wParams.put("StoreID", wStoreID);
        wParams.put("StoreAreaID", wStoreAreaID);
        wParams.put("StoreShelfID", wStoreShelfID);
        wParams.put("StoreStationID", wStoreStationID);
        wParams.put("BatchRecordID", wBatchRecordID);
        wParams.put("BatchRecordCode", wBatchRecordCode);
        wParams.put("ProjectNo", wProjectNo);
        wParams.put("MaterialID", wMaterialIDList);
        wParams.put("MaterialMarginNum", 0);

        return this.SelectPOList(wLoginUser, wParams, wPagination, wErrorCode);
    }

    public List<WMSStockRecord> WMS_QueryStockRecordList(BMSEmployee wLoginUser, int wFactoryID, int wStoreID, List<Integer> wMaterialIDList,
                                                         Pagination wPagination,
                                                         OutResult<Integer> wErrorCode) {
        Map<String, Object> wParams = new HashMap<String, Object>();
        wParams.put("FactoryID", wFactoryID);
        wParams.put("StoreID", wStoreID);
        wParams.put("MaterialID", wMaterialIDList);
        wParams.put("MaterialMarginNum", 0);

        return this.SelectPOList(wLoginUser, wParams, wPagination, wErrorCode);
    }


    public List<WMSStockRecord> WMS_QueryStockRecordList(BMSEmployee wLoginUser, int wFactoryID, List<Integer>  wStoreStationID,int wMaterialID,
                                                         Pagination wPagination,
                                                         OutResult<Integer> wErrorCode) {
        Map<String, Object> wParams = new HashMap<String, Object>();
        wParams.put("FactoryID", wFactoryID);
        wParams.put("StoreStationID", wStoreStationID);
        wParams.put("MaterialID", wMaterialID);
        wParams.put("MaterialMarginNum", 0);

        return this.SelectPOList(wLoginUser, wParams, wPagination, wErrorCode);
    }


    /**
     * 库存查询
     *
     * @param wLoginUser
     * @param wFactoryID
     * @param wStoreID
     * @param wStoreRegionID
     * @param wStoreAreaID
     * @param wStoreShelfID
     * @param wStoreStationID
     * @param wMaterialIDList
     * @param wBatchRecordID
     * @param wProjectNo
     * @param wCustomerID
     * @param wSupplierID
     * @param wStockTypeID
     * @param wStockStatus
     * @param wPagination
     * @param wErrorCode
     * @return
     */
    public List<WMSStock> WMS_QueryStockCountList(
            BMSEmployee wLoginUser, int wFactoryID, int wStoreID, int wStoreRegionID, int wStoreAreaID,
            int wStoreShelfID, int wStoreStationID, List<Integer> wMaterialIDList, int wBatchRecordID, String wBatchRecordCode, String wProjectNo,
            int wCustomerID, int wSupplierID, int wStockTypeID, int wStockStatus, int wHasItem, Pagination wPagination,
            OutResult<Integer> wErrorCode) {
        List<WMSStock> wResult = new ArrayList<WMSStock>();
        wErrorCode.set(0);

        try {
            if (wMaterialIDList == null)
                wMaterialIDList = new ArrayList<>();
            wMaterialIDList.removeIf(p -> p <= 0);

            List<String> wGroupByFiled = new ArrayList<String>();
            wGroupByFiled.add("t.MaterialID");
            if (wFactoryID == 0) {
                wGroupByFiled.add("t.FactoryID");
            }
            if (wStoreStationID == 0) {
                wGroupByFiled.add("t.StoreStationID");
            } else if (wStoreShelfID == 0) {
                wGroupByFiled.add("t.StoreShelfID");
            } else if (wStoreAreaID == 0) {
                wGroupByFiled.add("t.StoreAreaID");
            } else if (wStoreRegionID == 0) {
                wGroupByFiled.add("t.StoreRegionID");
            } else if (wStoreID == 0) {
                wGroupByFiled.add("t.StoreID");
            }

            // Step02:查询
            Map<String, Object> wParwms = new HashMap<String, Object>();
            String wSQLText = "";
            wSQLText = StringUtils.Format(
                    "Select t.MaterialID AS ID,t.FactoryID,t.StoreID,t.StoreRegionID,t.StoreAreaID," +
                            " t.StoreShelfID, t.StoreStationID,t.MaterialID,t.UnitID," +
                            " ifnull(sum(t.MaterialMarginNum),0) as MaterialNum,ifnull(sum(t.MaterialFreezeNum),0) as FreezeNum " +
                            " from {0}.wms_stockrecord t  where t.ID>0 AND t.MaterialMarginNum>0" +
                            " AND (:CustomerID<=0 or  t.CustomerID=:CustomerID) " +
                            " AND (:SupplierID<=0 or  t.SupplierID=:SupplierID) " +
                            " AND (:StockTypeID<=0 or  t.StockTypeID=:StockTypeID) " +
                            " AND (:StockStatus<=0 or  t.StockStatus=:StockStatus) " +
                            " AND (:FactoryID<=0 or  t.FactoryID=:FactoryID)" +
                            " AND (:StoreRegionID<=0 or  t.StoreRegionID=:StoreRegionID) " +
                            " AND (:StoreID<=0 or  t.StoreID=:StoreID) " +
                            " AND (:StoreAreaID<=0 or  t.StoreAreaID=:StoreAreaID)" +
                            " AND (:StoreShelfID<=0 or  t.StoreShelfID=:StoreShelfID)" +
                            " AND (:StoreStationID<=0 or  t.StoreStationID=:StoreStationID)" +
                            " AND (:MaterialID= '''' or  t.MaterialID in (''{2}''))" +
                            " AND (:BatchRecordID<=0 or  t.BatchRecordID=:BatchRecordID)" +
                            " and (:BatchRecordCode =''''  or  t.BatchRecordCode=:BatchRecordCode) " +
                            " and (:ProjectNo =''''  or  t.ProjectNo=:ProjectNo) group by {1}",
                    super.getDBName(), StringUtils.Join(",", wGroupByFiled)
                    , StringUtils.Join("','", wMaterialIDList));

            wSQLText = this.DMLChange(wSQLText);

            wParwms.put("FactoryID", wFactoryID);
            wParwms.put("CustomerID", wCustomerID);
            wParwms.put("SupplierID", wSupplierID);
            wParwms.put("StockTypeID", wStockTypeID);
            wParwms.put("StockStatus", wStockStatus);
            wParwms.put("StoreRegionID", wStoreRegionID);
            wParwms.put("StoreID", wStoreID);
            wParwms.put("StoreAreaID", wStoreAreaID);
            wParwms.put("StoreShelfID", wStoreShelfID);
            wParwms.put("StoreStationID", wStoreStationID);
            wParwms.put("BatchRecordID", wBatchRecordID);
            wParwms.put("BatchRecordCode", wBatchRecordCode);
            wParwms.put("ProjectNo", wProjectNo);
            wParwms.put("MaterialID", StringUtils.Join("','", wMaterialIDList));


            wResult = super.QueryForList(wSQLText, wParwms, wPagination, WMSStock.class);

            FMCFactory wFMCFactory;
            WMSStore wWMSStore;
            WMSStoreRegion wWMSStoreRegion;
            WMSStoreArea wWMSStoreArea;
            WMSStoreShelf wWMSStoreShelf;
            WMSStoreStation wWMSStoreStation;
            MSSMaterial wMSSMaterial;
            MSSUnit wMSSUnit;

            List<WMSStockRecord> wStockRecordList = null;
            if (wHasItem == 1) {
                wStockRecordList = this.WMS_QueryStockRecordList(wLoginUser, wFactoryID, wStoreID, wStoreRegionID, wStoreAreaID, wStoreShelfID,
                        wStoreStationID, wMaterialIDList, wBatchRecordID, wBatchRecordCode, wProjectNo, wCustomerID, wSupplierID,
                        wStockTypeID, wStockStatus, Pagination.getMaxSize(WMSStockRecord.class), wErrorCode);

            }

            for (WMSStock wWMSStock : wResult) {
                if (wWMSStock.FactoryID > 0) {
                    wFMCFactory = CacheUtils.GetCacheInfo(FMCFactory.class, wWMSStock.FactoryID, "");
                    if (wFMCFactory != null && wFMCFactory.ID > 0) {
                        wWMSStock.FactoryCode = wFMCFactory.Code;
                        wWMSStock.FactoryName = wFMCFactory.Name;
                    }

                }
                if (wWMSStock.StoreID > 0) {
                    wWMSStore = CacheUtils.GetCacheInfo(WMSStore.class, wWMSStock.StoreID, "");
                    if (wWMSStore != null && wWMSStore.ID > 0) {
                        wWMSStock.StoreCode = wWMSStore.Code;
                        wWMSStock.StoreName = wWMSStore.Name;
                    }

                }
                if (wWMSStock.StoreRegionID > 0) {
                    wWMSStoreRegion = CacheUtils.GetCacheInfo(WMSStoreRegion.class, wWMSStock.StoreRegionID, "");
                    if (wWMSStoreRegion != null && wWMSStoreRegion.ID > 0) {
                        wWMSStock.StoreRegionCode = wWMSStoreRegion.Code;
                        wWMSStock.StoreRegionName = wWMSStoreRegion.Name;
                    }

                }
                if (wWMSStock.StoreAreaID > 0) {
                    wWMSStoreArea = CacheUtils.GetCacheInfo(WMSStoreArea.class, wWMSStock.StoreAreaID, "");
                    if (wWMSStoreArea != null && wWMSStoreArea.ID > 0) {
                        wWMSStock.StoreAreaCode = wWMSStoreArea.Code;
                        wWMSStock.StoreAreaName = wWMSStoreArea.Name;
                    }

                }
                if (wWMSStock.StoreShelfID > 0) {
                    wWMSStoreShelf = CacheUtils.GetCacheInfo(WMSStoreShelf.class, wWMSStock.StoreShelfID, "");
                    if (wWMSStoreShelf != null && wWMSStoreShelf.ID > 0) {
                        wWMSStock.StoreShelfCode = wWMSStoreShelf.Code;
                        wWMSStock.StoreShelfName = wWMSStoreShelf.Name;
                    }

                }
                if (wWMSStock.StoreStationID > 0) {
                    wWMSStoreStation = CacheUtils.GetCacheInfo(WMSStoreStation.class, wWMSStock.StoreStationID, "");
                    if (wWMSStoreStation != null && wWMSStoreStation.ID > 0) {
                        wWMSStock.StoreStationCode = wWMSStoreStation.Code;
                        wWMSStock.StoreStationName = wWMSStoreStation.Name;
                    }

                }

                if (wWMSStock.MaterialID > 0) {
                    wMSSMaterial = CacheUtils.GetCacheInfo(MSSMaterial.class, wWMSStock.MaterialID, "");
                    if (wMSSMaterial != null && wMSSMaterial.ID > 0) {
                        wWMSStock.MaterialCode = wMSSMaterial.Code;
                        wWMSStock.MaterialName = wMSSMaterial.Name;
                    }

                }
                if (wWMSStock.UnitID > 0) {
                    wMSSUnit = CacheUtils.GetCacheInfo(MSSUnit.class, wWMSStock.UnitID, "");
                    if (wMSSUnit != null && wMSSUnit.ID > 0) {
                        wWMSStock.UnitCode = wMSSUnit.Code;
                        wWMSStock.UnitText = wMSSUnit.Name;
                    }

                }

                if (wHasItem == 1 && wErrorCode.Result == 0 && wStockRecordList != null && wStockRecordList.size() > 0) {
                    for (WMSStockRecord wmsStockRecord : wStockRecordList) {
                        if ((wFactoryID == 0 && wWMSStock.FactoryID != wmsStockRecord.FactoryID)
                                || (wStoreID == 0 && wWMSStock.StoreID != wmsStockRecord.StoreID)
                                || (wStoreRegionID == 0 && wWMSStock.StoreRegionID != wmsStockRecord.StoreRegionID)
                                || (wStoreAreaID == 0 && wWMSStock.StoreAreaID != wmsStockRecord.StoreAreaID)
                                || (wStoreShelfID == 0 && wWMSStock.StoreShelfID != wmsStockRecord.StoreShelfID)
                                || (wStoreStationID == 0 && wWMSStock.StoreStationID != wmsStockRecord.StoreStationID))

                            continue;
                        wWMSStock.StockRecordList.add(wmsStockRecord);
                    }

                }
            }


            // Step03:配置系统
        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error("WMS_QueryStockList", ex);
        }
        return wResult;
    }


    public List<WMSStock> WMS_QueryStockCountList(
            BMSEmployee wLoginUser, int wFactoryID, List<Integer> wMaterialIDList, Pagination wPagination,
            OutResult<Integer> wErrorCode) {
        List<WMSStock> wResult = new ArrayList<WMSStock>();
        wErrorCode.set(0);

        try {

            wResult = this.WMS_QueryStockCountList(wLoginUser, wFactoryID,
                    -1, -1, -1, -1, -1,
                    wMaterialIDList, -1, "", "", -1, -1, -1,
                    -1, 0, wPagination, wErrorCode);

            // Step03:配置系统
        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error("WMS_QueryStockCountList", ex);
        }
        return wResult;
    }

    public WMSStock WMS_QueryStock(
            BMSEmployee wLoginUser, int wStoreStationID, int wMaterialID, int wBatchRecordID, String wBatchRecordCode, String wProjectNo,
            int wCustomerID, int wSupplierID, int wStockTypeID, int wStockStatus, OutResult<Integer> wErrorCode) {
        WMSStock wResult = new WMSStock();
        try {
            if (wMaterialID <= 0 || wStoreStationID <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            List<WMSStock> wList = this.WMS_QueryStockCountList(wLoginUser, -1,
                    -1, -1, -1, -1, wStoreStationID,
                    StringUtils.parseListArgs(wMaterialID), wBatchRecordID, wBatchRecordCode, wProjectNo, wCustomerID, wSupplierID, wStockTypeID,
                    wStockStatus, 1, Pagination.getNewDefault(), wErrorCode);
            if (wList.size() > 0) {
                wResult = wList.get(0);
            }
        } catch (Exception e) {
            wErrorCode.set(ExceptionTypes.Exception.getValue());
            log.error("WMS_QueryStock", e);
        }

        return wResult;
    }

    public WMSStock WMS_QueryStock(
            BMSEmployee wLoginUser, int wStoreID, int wStoreRegionID, int wStoreAreaID,
            int wStoreShelfID, int wStoreStationID, int wMaterialID, int wBatchRecordID, String wBatchRecordCode, String wProjectNo,
            int wCustomerID, int wSupplierID, int wStockTypeID, int wStockStatus, OutResult<Integer> wErrorCode) {
        WMSStock wResult = new WMSStock();
        try {
            if (wMaterialID <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }
            if (wStoreID == 0 || wStoreRegionID == 0 || wStoreAreaID == 0 || wStoreShelfID == 0 || wStoreStationID == 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            List<WMSStock> wList = this.WMS_QueryStockCountList(wLoginUser, -1,
                    wStoreID, wStoreRegionID, wStoreAreaID, wStoreShelfID, wStoreStationID,
                    StringUtils.parseListArgs(wMaterialID), wBatchRecordID, wBatchRecordCode, wProjectNo, wCustomerID, wSupplierID, wStockTypeID,
                    wStockStatus, 1, Pagination.getNewDefault(), wErrorCode);
            if (wList.size() > 0) {
                wResult = wList.get(0);
            }
        } catch (Exception e) {
            wErrorCode.set(ExceptionTypes.Exception.getValue());
            log.error("WMS_QueryStock", e);
        }

        return wResult;
    }


    public void WMS_DeleteStockRecord(BMSEmployee wLoginUser, WMSStockRecord wWMSStockRecord, OutResult<Integer> wErrorCode) {

        try {
            String wSqlText = StringUtils.Format(" delete t from {0} t left join {1} t2 on t.ID=t2.RecordID where t.ID={3} AND ifNull(t2.ID,0)=0",
                    this.getTableName(), getTableName("wms_stockrecord_operate"), wWMSStockRecord.ID);

            this.Update(wSqlText, new HashMap<>());

        } catch (Exception e) {
            wErrorCode.set(ExceptionTypes.Exception.getValue());
            log.error("WMS_DeleteStockRecord", e);
        }
    }


}
